﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;

using System.Data.Objects;
using System.Data.Entity.Infrastructure;
using log4net;
using System.Web.Security;

namespace TsCore
{
    internal class SportHandler
    {
        private static SportHandler _instance;
        public List<Team> Teams { get; set; } //Estas listas no van me parece 
        public List<Sport> Sports { get; set; }

        //Singleton
        public static SportHandler Instance
        {
            get
            {
                if (_instance == null)
                {
                    _instance = new SportHandler();
                }
                return _instance;
            }
        }

        #region Sports Management

        public List<Sport> GetAllSports()
        {
            List<Sport> retList = new List<Sport>();
            try
            {
                using (TsContext ctx = new TsContext())
                {
                    retList = (from s in ctx.Sports
                               select s).ToList<Sport>();
                }
            }
            catch (Exception ex)
            {
                LogManager.GetLogger(Membership.GetUser().UserName).Error("Error al obtener los deportes", ex);
            }
            return retList;
        }

        public void CreateNewSport(String SportName)
        {
            try
            {
                if (this.GetSport(SportName) == null)
                {
                    using (TsContext ctx = new TsContext())
                    {
                        Sport newSport = new Sport();
                        newSport.Name = SportName;
                        ctx.Sports.Add(newSport);
                        ctx.SaveChanges();
                    }
                }
                else
                {
                    throw new Exception("Duplicate Sport");
                }
            }
            catch (Exception ex)
            {
                LogManager.GetLogger(Membership.GetUser().UserName).Error("Error al crear un Deporte " + SportName, ex);
            }
        }

        public void UpdateSport(Sport UpdatedSport)
        {
            try
            {
                if (this.GetSport(UpdatedSport.Name) == null)
                {
                    using (TsContext ctx = new TsContext())
                    {
                        ctx.Sports.Attach(UpdatedSport);
                        ctx.Entry(UpdatedSport).State = EntityState.Modified;
                        ctx.SaveChanges();
                    }
                }
            }
            catch (Exception ex)
            {
                LogManager.GetLogger(Membership.GetUser().UserName).Error("Error al actualizar un deporte", ex);
            }
        }

        public Sport GetSport(String SportName)
        {
            Sport retSport = null;
            try
            {
                using (TsContext ctx = new TsContext())
                {
                    retSport = (from s in ctx.Sports.Include("Teams")
                                where s.Name == SportName
                                select s).SingleOrDefault();
                }
            }
            catch (Exception ex)
            {
                LogManager.GetLogger(Membership.GetUser().UserName).Error("Error al obtener el deporte: " + SportName, ex);
            }
            return retSport;
        }

        public Sport GetSport(int SportId)
        {
            Sport retSport = null;
            try
            {
                using (TsContext ctx = new TsContext())
                {
                    retSport = (from s in ctx.Sports
                                where s.SportId == SportId
                                select s).SingleOrDefault();
                }
            }
            catch (Exception ex)
            {
                LogManager.GetLogger(Membership.GetUser().UserName).Error("Error al obtener el Deporte: " + SportId, ex);
                return null;
            }
            return retSport;
        }

        public Sport GetSportWithTeams(int SportId)
        {
            Sport retSport = null;
            try
            {
                using (TsContext ctx = new TsContext())
                {
                    retSport = (from s in ctx.Sports.Include("Teams")
                                where s.SportId == SportId
                                select s).SingleOrDefault();
                }
            }
            catch (Exception ex)
            {
                LogManager.GetLogger(Membership.GetUser().UserName).Error("Error al obtener los Deportes con Equipos", ex);
            }
            return retSport;
        }

        public void RemoveSport(Sport sport)
        {
            try
            {
                //Borramos todos los teams del Sport
                foreach (Team team in sport.Teams)
                {
                    this.RemoveTeam(this.GetTeam(team.TeamId));
                }

                Sport toRemoveSport = this.GetSport(sport.SportId);
                using (TsContext ctx = new TsContext())
                {
                    ctx.Sports.Attach(toRemoveSport);
                    ctx.Sports.Remove(toRemoveSport);
                    ctx.SaveChanges();
                }
            }
            catch (Exception ex)
            {
                LogManager.GetLogger(Membership.GetUser().UserName).Error("Error al eliminar un Deporte", ex);
            }
        }

        #endregion

        #region Teams Management

        private Boolean validateTeam(Team team)
        {
            Boolean isValid = false;
            try
            {
                isValid = (team != null && team.Name != "" && team.Image != "");

                var check =
                    from tim in Teams
                    where tim.Name == team.Name && tim.Image == team.Image
                    select tim;

                isValid &= (check.Distinct().Count() == 0);
            }
            catch (Exception ex)
            {
                LogManager.GetLogger(Membership.GetUser().UserName).Error("Error al validar un Equipo", ex);
            }
            return isValid;
        }

        public void createTeam(String Name, String Image)
        {
            Team team = new Team(Name, Image);
            try
            {
                if (validateTeam(team))
                {
                    TsContext tsx = new TsContext(); //TODO: Hay que usar using o sino hacer dispose
                    Teams.Add(team);
                    tsx.Teams.Add(team);
                    tsx.SaveChanges();
                }
                else
                {
                    Exception ex = new Exception("El team " + team.ToString() + "no es válido");
                    throw ex;
                }
            }
            catch (Exception ex)
            {
                LogManager.GetLogger(Membership.GetUser().UserName).Error("Error al crear un Equipo", ex);
            }
        }

        public void modifyTeamName(Team team, String Name)
        {
            Team teamToCheck = new Team(Name, team.Image);
            if (validateTeam(teamToCheck))
            {
                foreach (Team t in Teams)
                {
                    if (team.Name.CompareTo(t.Name) == 0 && team.Image.CompareTo(t.Image) == 0)
                    {
                        t.Name = Name;
                    }
                }
            }

        }

        public void RemoveTeam(Team team)
        {
            try
            {
                using (TsContext ctx = new TsContext())
                {
                    List<Match> matchesForCurrentTeam = TsSystem.Instance.GetMatchesForTeam(team);
                    List<Match> toRemoveMatches = new List<Match>();
                    foreach (Match match in TsSystem.Instance.GetAllMatches())
                    {
                        if (matchesForCurrentTeam.Contains(match))
                        {
                            toRemoveMatches.Add(match);
                        }
                    }

                    foreach (Match match in toRemoveMatches)
                    {
                        ctx.Matches.Attach(match);
                        ctx.Matches.Remove(match);
                    }

                    foreach (Comment toAttach in team.Comments)
                    {
                        ctx.Comments.Attach(toAttach);
                    }

                    ctx.Teams.Attach(team);
                    ctx.Teams.Remove(team);
                    ctx.SaveChanges();
                }
            }
            catch (Exception ex)
            {
                LogManager.GetLogger(Membership.GetUser().UserName).Error("Error al eliminar un Equipo", ex);
            }
        }

        public List<Team> GetAllTeams()
        {
            List<Team> retList = new List<Team>();
            try
            {
                using (TsContext ctx = new TsContext())
                {
                    retList = (from t in ctx.Teams
                               select t).ToList<Team>();
                }
            }
            catch (Exception ex)
            {
                LogManager.GetLogger(Membership.GetUser().UserName).Error("Error al obtener los Equipos", ex);
            }
            return retList;
        }

        public List<Team> GetAllTeamsSortedByName(bool DescendingOrder)
        {
            List<Team> retList = new List<Team>();
            try
            {
                if (DescendingOrder)
                {
                    using (TsContext ctx = new TsContext())
                    {
                        retList = (from t in ctx.Teams.Include("Sport")
                                   orderby t.Name descending
                                   select t).ToList<Team>();
                    }
                }
                else
                {
                    using (TsContext ctx = new TsContext())
                    {
                        retList = (from t in ctx.Teams.Include("Sport")
                                   orderby t.Name ascending
                                   select t).ToList<Team>();
                    }
                }
            }
            catch (Exception ex)
            {
                LogManager.GetLogger(Membership.GetUser().UserName).Error("Error al obtener los Equipos ordenados por nombre", ex);
            }
            return retList;
        }

        public List<Team> GetAllTeamsFilteredByName(String NamePart)
        {
            List<Team> retList = new List<Team>();
            try
            {
                using (TsContext ctx = new TsContext())
                {
                    retList = (from t in ctx.Teams.Include("Sport")
                               where t.Name.StartsWith(NamePart)
                               orderby t.Name descending
                               select t).ToList<Team>();
                }
            }
            catch (Exception ex)
            {
                LogManager.GetLogger(Membership.GetUser().UserName).Error("Error al obtener los Equipos filtrados por nombre", ex);
            }
            return retList;
        }

        public List<Team> GetAllTeamsWithFollowers()
        {
            List<Team> retList = new List<Team>();
            try
            {
                using (TsContext ctx = new TsContext())
                {
                    retList = (from t in ctx.Teams.Include("Followers")
                               select t).ToList<Team>();
                }
            }
            catch (Exception ex)
            {
                LogManager.GetLogger(Membership.GetUser().UserName).Error("Error al crear un Equipo", ex);
            }
            return retList;
        }

        public void CreateNewTeam(String TeamName, String ImageUrl, List<Comment> CommentList, Sport TeamSport)
        {
            try
            {
                using (TsContext ctx = new TsContext())
                {
                    Team newTeam = new Team();

                    newTeam.Name = TeamName;
                    newTeam.Image = ImageUrl;
                    newTeam.Comments = CommentList;
                    ctx.Sports.Attach(TeamSport);
                    newTeam.Sport = TeamSport;
                    ctx.Teams.Add(newTeam);

                    ctx.SaveChanges();
                }
            }
            catch (Exception ex)
            {
                LogManager.GetLogger(Membership.GetUser().UserName).Error("Error al crear un Equipo: " + TeamName + " - " + ImageUrl, ex);
            }
        }

        public Team CreateNewDummyTeam(String TeamName, String ImageUrl, List<Comment> CommentList, Sport TeamSport)
        {
            Team toReturnTeam = new Team();
            try
            {
                Team newTeam = new Team();
                using (TsContext ctx = new TsContext())
                {
                    newTeam.Name = TeamName;
                    newTeam.Image = ImageUrl;
                    newTeam.Comments = CommentList;
                    newTeam.IsDummyTeam = true;
                    ctx.Sports.Attach(TeamSport);
                    newTeam.Sport = TeamSport;
                    toReturnTeam = ctx.Teams.Add(newTeam);
                    ctx.SaveChanges();
                }
             }
            catch (Exception ex)
            {
                LogManager.GetLogger(Membership.GetUser().UserName).Error("Error al crear un Equipo Dummy", ex);
            }
            return toReturnTeam;
        }

        public Team GetTeam(int TeamId)
        {
            Team retTeam = null;
            try
            {
                using (TsContext ctx = new TsContext())
                {
                    retTeam = (from t in ctx.Teams.Include("Sport").Include("Comments")
                               where t.TeamId == TeamId
                               select t).SingleOrDefault();
                }
            }
            catch (Exception ex)
            {
                LogManager.GetLogger(Membership.GetUser().UserName).Error("Error al obtener un Equipo", ex);
            }
            return retTeam;
        }
        
        public Team GetTeamWithoutIncludes(int TeamId)
        {
            Team retTeam = null;
            try
            {
                using (TsContext ctx = new TsContext())
                {

                    retTeam = (from t in ctx.Teams
                               where t.TeamId == TeamId
                               select t).SingleOrDefault();
                }
            }
            catch (Exception ex)
            {
                LogManager.GetLogger(Membership.GetUser().UserName).Error("Error al obtener el equipo", ex);
            }
            return retTeam;
        }

        public void UpdateTeam(Team UpdatedTeam)
        {
            try
            {
                using (TsContext ctx = new TsContext())
                {
                    Team originalTeam = (from t in ctx.Teams.Include("Sport").Include("Comments")
                                         where t.TeamId == UpdatedTeam.TeamId
                                         select t).SingleOrDefault();                    

                    foreach (Comment c in UpdatedTeam.Comments)
                    {
                        if (c.CommentId == 0)
                        {
                            ctx.Comments.Add(c);
                        }
                    }
                    if (ctx.Entry(UpdatedTeam).State == System.Data.EntityState.Detached)
                    {
                        ctx.Teams.Attach(originalTeam);
                        if (UpdatedTeam.Comments != null)
                        {
                            originalTeam.Comments = UpdatedTeam.Comments;
                        }
                        if (UpdatedTeam.Sport.SportId != originalTeam.Sport.SportId)
                        {
                            ctx.Sports.Attach(UpdatedTeam.Sport);
                            originalTeam.Sport = UpdatedTeam.Sport;
                        }                        
                    }
                    ctx.SaveChanges();
                }
            }
            catch (Exception ex)
            {
                LogManager.GetLogger(Membership.GetUser().UserName).Error("Error al actualizar un Equipo", ex);
            }
        }

        public List<Comment> GetCommentsFromTeam(Team Team)
        {
            return GetTeam(Team.TeamId).Comments;
        }
        #endregion
    }
}





